
// This file is part of Module Proxy.

// Module Proxy is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Module Proxy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Module Proxy.  If not, see <https://www.gnu.org/licenses/>.


//         Copyright (C) 2021 - 2030  关中麦客  
//         All rights reserved
//
//         cache.rs
//         任务缓存
//
//         created by 关中麦客 1036038462@qq.com

use std::collections::HashMap;
use tokio::sync::mpsc::{Sender, channel};
use tokio::sync::Mutex; 
use tokio::sync::oneshot;
use once_cell::sync::OnceCell;

// use log;
use super::util;

//全局 channel tx
static TX: OnceCell<Mutex<Sender<Method>>> = OnceCell::new();                  

/// channel 接口
// #[derive(Debug)]
enum Method
{
    Set 
    {
        key: String,     //视频唯一编码
    },
    Get
    {
        key: String,
        rsp: oneshot::Sender<Option<u32>>, 
    },
    Del
    {
        key: String,
    },
}

// 初始化
pub fn init()
{
    //初始化channel tx rx
    let (tx, mut rx) = channel(32);

    //初始化缓存
    TX.get_or_init(||{
        Mutex::new(tx)
    });

    //缓存
    let mut cache: HashMap<String, u32> = HashMap::new();   

    //接收任务 --------------------------------------------
    tokio::spawn(async move {

        while let Some(method) = rx.recv().await
        {
            match method
            {
                Method::Set{key} =>
                {
                    cache.insert(key, util::sec_timestamp());
                },
                Method::Get{key, rsp} =>
                {
                    if let Some(timestamp) = cache.get(&key)
                    {
                        let _ = rsp.send(Some(*timestamp));
                    }
                    else
                    {
                        let _ = rsp.send(None);
                    }                    
                },
                Method::Del{key} =>
                {
                    cache.remove(&key);
                },
            }                  
        }// while
    });
}

///发送channel消息 set
pub async fn set(key: String)
{
    if let Some(mutex) = TX.get()
    {
        let tx = mutex.lock().await;
        let tx = tx.clone();
        let method = Method::Set{key};
        let _ = tx.send(method).await;        //发送
    }    
}

/// 发送channel消息 get
pub async fn get(key: &str) -> Option<u32>
{
    let (rsp_tx, rsp_rx) = oneshot::channel();
    if let Some(mutex) = TX.get()
    {
        let tx = mutex.lock().await;
        let tx = tx.clone();
        let method = Method::Get{key: key.to_string(), rsp: rsp_tx};
        let _ = tx.send(method).await;  //发送
        if let Ok(rsp) = rsp_rx.await   //接收
        {
            return rsp;
        }
    }

    None
}

///发送channel消息 del
pub async fn del(key: String)
{
    if let Some(mutex) = TX.get()
    {
        let tx = mutex.lock().await;
        let tx = tx.clone();
        let method = Method::Del{key};
        let _ = tx.send(method).await;        //发送
    }    
}